/* CSIM-based program to simulate a token-ring system
 * Service Discipline: Exhaustive service
*/

#include "csim.h"
#include <stdio.h>

#define	SVTM	90	/*mean of service time distribution */
#define NARS	20	/*number of arrivals to be simulated*/
#define TPTM 	1	//Token-passing time between stations

#define NVALUE 	10
#define SVALUE 	10	//Number of different values of NST
#define SMAX 	19	//Maximum number of stations

FACILITY f[SMAX];		/*pointers for facilities */
EVENT done;				/*pointer for counter */
TABLE tbl;				/*pointer for table */
QTABLE qtbl;			/*pointer for qhistogram */
int cnt;				/*number of active tasks*/
FILE *fp;
void cust();
int cnt_station[SMAX];
int token;
int passnum;				//token passing times between two stations

void sim()				/*1st process - named sim */
{
	//printf("up to 1 OK\r\n");
	int n, dis, i, k, d, s;
	double IATM;				//Inter-arrival time at each station
	int NST;					//number of stations
	double delay[NVALUE];		//record the delay for each IATM
	double cycletm[NVALUE];
	double runtime[SVALUE];		//record the runtime for each NST value
	float cpu_start;
	TIME sim_start;
	//printf("up to 2 OK\r\n");
	
	fp = fopen("q5-2_report.out", "w");
	set_output_file(fp);
	set_model_name("Token ring: One-at-a-time");
	create("sim");						/*required create statement	*/
	tbl = table("resp tms");				/*initialize table 		*/
	qtbl = qhistogram("num in sys", 10l);	/*initialize qhistogram	*/
	facility_set(f, "station", SMAX);
	//printf("up to 3 OK\r\n");
	
	for(n = 0; n < SVALUE; n ++) {
		cpu_start = cputime();
		NST = 10+n;
		//printf("NST = %d begins\r\n", NST);
		cnt = NST*NARS;
		//printf("up to 3.1 OK\r\n");
		for(dis = 0; dis < NVALUE; dis ++) {
			reset();
			for(s = 0; s < NST; s ++) {
				cnt_station[s] = NARS;
			}
			done = event("done");			/*initialize event*/
			sim_start = clock;
			token = 0;
			//printf("up to 3.2 OK\r\n");
			IATM = (100 + 50*dis)/NST;
			passnum = 0;
			delay[dis] = 0;
			//printf("up to 3.3 OK\r\n");
			for(i = 0; i< NST*NARS; i++) {
				hold(expntl(IATM));		/*hold interarrival*/
				cust(i%NST, NST);
			}
			//printf("up to 3.4 OK\r\n");
			//wait(done);				/*wait until all done*/
			wait(event_list_empty);
			//printf("up to 3.5 OK\r\n");
			for (k = 0; k < NST; k ++) {
				delay[dis] += resp(f[k]);
			}
			//printf("up to 3.6 OK\r\n");
			delay[dis] = delay[dis] / NST;
			cycletm[dis] = (clock - sim_start) / (passnum/NST);
		}
		//printf("up to 3.7 OK\r\n");
		runtime[n] = (double)(cputime()-cpu_start);
		if (NST == 10) {
			printf("\r\n\r\n IATM vs. delays of packets (one '*' = 5)");
			for (d=0; d<NVALUE; d++){
				printf("\n  %d\t|", 100+50*d);
				//printf("delay[%d] = %d\r\n", d, delay[d]);
				for (k=0; k*5 < delay[d]; k++)
					printf("*");
			}
			printf("\r\n\r\n IATM vs. cycle-time of token (one '*' = 10)");
			for (d=0; d<NVALUE; d++){
				printf("\n  %d\t|", 100+50*d);
				for (k=0; k*10 < cycletm[d]; k++)
					printf("*");
			}
			printf("\r\n");
		}
	}
	//printf("up to 4 OK\r\n");
	printf("\r\n# stations vs. run time (one '*' = 50 msec)");
	for (d = 0; d < SVALUE; d++){
		printf("\nN=%5d |", 10+d);
		for (k=0; k*0.05 < runtime[d]; k++)
			printf("*");
	}
	printf("\r\n\r\n");
	//printf("up to 5 OK\r\n");
}

void cust(int s, int NST) {
	create("job");	/*required create statement*/
	TIME t1;
	t1 = clock;					/*time of request */
	note_entry(qtbl);			/*note arrival */
	int timeout = 0;
	if (cnt_station[s] == 0) {
		token = (s+1)%NST;
		passnum ++;
		hold(TPTM);
	}
	else {
		while (token != s) {	// if the station does not hold the token
			hold(1);			// hold until the station gets the token
			timeout ++;
			if (timeout == 100) {
				timeout = 0;
				token = (token+1)%NST;
			}
			//printf("station %d is holding when token = %d\r\n", s, token);
		}
		//printf("station %d gets the token when token = %d!\r\n", s, token);
		reserve(f[s]);				/*reserve facility f*/
			hold(expntl(SVTM));		/*hold service time*/
		release(f[s]);				/*release facility f*/
		cnt --;
		cnt_station[s] --;
		if(cnt == 0)
			set(done);				/*if last arrival, signal*/
		record(clock-t1, tbl);		/*record response time*/
		note_exit(qtbl);			/*note departure */
		/* only when the queue is empty then pass the token on 	*/
		if (qlength(f[s]) == 0) {
			token = (s+1)%NST;		//pass the token on
			passnum ++;
			hold(TPTM);
		}
	}
}
